package border;

import static org.junit.Assert.*;

import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;

import square.Direction;
import square.NormalSquare;

public class BorderTest {
	
	
	@BeforeClass
	public static void setUpBeforeClass()  {
	}


	@Before
	public void setUp() {
		square1 = new NormalSquare();
		square2 = new NormalSquare();
		square3 = new NormalSquare();
		square4 = new NormalSquare();
		
		directionOfBorder = Direction.NORTH;
		isClosedDoor = false;
		isSlipperyWall = false;
		
		
		
	}
	
//////////////////////////////////////////////////////////////////////////////////////
	@Test
	public void constructor_twoSquares(){
		 Door door = new Door(square1, square2, directionOfBorder, isClosedDoor);
		 Wall wall = new Wall(square3, square4, directionOfBorder, isSlipperyWall);
		 
		 assertFalse(door.isClosed());
		 assertFalse(wall.isSlippery());
		 assertFalse(door.isTerminated());
		 assertFalse(wall.isTerminated());
		 assertFalse(door.isClosed());
		 assertFalse(wall.isSlippery());
		 assertEquals(square1.getBorder(directionOfBorder), door);
		 assertEquals(square2.getBorder(directionOfBorder.getOpposite()), door);
		 assertEquals(square3.getBorder(directionOfBorder), wall);
		 assertEquals(square4.getBorder(directionOfBorder.getOpposite()), wall);
		 
	}
	
	@Test
	public void constructor_oneSquare(){
		Door door = new Door(square1, directionOfBorder, isClosedDoor);
		Wall wall = new Wall(square3, directionOfBorder, isSlipperyWall);
		
		assertFalse(door.isClosed());
		assertFalse(wall.isSlippery());
		assertFalse(door.isTerminated());
		assertFalse(wall.isTerminated());
		assertFalse(door.isClosed());
		assertFalse(wall.isSlippery());
		assertEquals(square1.getBorder(directionOfBorder), door);
		assertEquals(square3.getBorder(directionOfBorder), wall);
		 
	}
//////////////////////////////////////////////////////////////////////////////////////////////	
	@Test
	public void terminateBorderWithOneSquare(){
		Door door = new Door(square1, directionOfBorder, isClosedDoor);
		Wall wall = new Wall(square3, directionOfBorder, isSlipperyWall);		
		
		door.terminate();
		wall.terminate();
		
		assertTrue(door.isTerminated());
		assertTrue(wall.isTerminated());
		assertEquals(door.getSquare1(), null);
		assertEquals(door.getSquare2(), null);
		assertEquals(wall.getSquare1(), null);
		assertEquals(wall.getSquare2(), null);
		assertFalse(square1.hasBorder(door));
		assertFalse(square3.hasBorder(wall));
	} 
	
	@Test
	public void terminateBorderWithTwoSquares(){
		Door door = new Door(square1, square2, directionOfBorder, isClosedDoor);
		Wall wall = new Wall(square3, square4, directionOfBorder, isSlipperyWall);
		
		door.terminate();
		wall.terminate();
		
		assertTrue(door.isTerminated());
		assertTrue(wall.isTerminated());
		assertEquals(door.getSquare1(), null);
		assertEquals(door.getSquare2(), null);
		assertEquals(wall.getSquare1(), null);
		assertEquals(wall.getSquare2(), null);
		assertFalse(square1.hasBorder(door));
		assertFalse(square2.hasBorder(door));
		assertFalse(square3.hasBorder(wall));
		assertFalse(square4.hasBorder(wall));
	}
	
///////////////////////////////////////////////////////////////////////////////////////////////
	
	@Test (expected = IllegalArgumentException.class)
	public void getOtherSquareTest_NonEffectiveSquareForDoor(){
		Door door = new Door(square1, directionOfBorder, isClosedDoor);
		door.getOtherSquare(null);
	}
	
	@Test (expected = IllegalArgumentException.class)
	public void getOtherSquareTest_NonEffectiveSquareForWall(){
		Wall wall = new Wall(square1, directionOfBorder, isSlipperyWall);
		wall.getOtherSquare(null);
	}
	
	@Test (expected = IllegalArgumentException.class)
	public void getOtherSquareTest_NoneOfTheSquaresForDoor(){
		Door door = new Door(square1, square2, directionOfBorder, isClosedDoor);
		door.getOtherSquare(square3);
	}
	
	@Test (expected = IllegalArgumentException.class)
	public void getOtherSquareTest_NoneOfTheSquaresForWall(){
		Wall wall = new Wall(square1, square2, directionOfBorder, isSlipperyWall);
		wall.getOtherSquare(square3);
	}
	
	@Test
	public void getOtherSquareTest_LegalCaseForDoor(){
		Door door = new Door(square1, square2, directionOfBorder, isClosedDoor);
		
		assertEquals(square2, door.getOtherSquare(square1));
		assertEquals(square1, door.getOtherSquare(square2));
		
	}
	
	@Test
	public void getOtherSquareTest_LegalCaseForWall(){
		Wall wall = new Wall(square1, square2, directionOfBorder, isSlipperyWall);
		
		assertEquals(square2, wall.getOtherSquare(square1));
		assertEquals(square1, wall.getOtherSquare(square2));
	}
	
///////////////////////////////////////////////////////////////////////////////////////////////
	
	@Test
	public void canHaveAsSquareTest_TerminatedDoorCase(){
		Door door = new Door(square1, square2, directionOfBorder, isClosedDoor);
		door.terminate();
		assertTrue(door.canHaveAsSquare(null));
	}
	
	@Test
	public void canHaveAsSquareTest_TerminatedWallCase(){
		Wall wall = new Wall(square1, square2, directionOfBorder, isSlipperyWall);
		wall.terminate();
		assertTrue(wall.canHaveAsSquare(null));
	}
	
	@Test
	public void canHaveAsSquareTest_LegalCaseForDoor(){
		Door door = new Door(square1, square2, directionOfBorder, isClosedDoor);
		assertTrue(door.canHaveAsSquare(square3));
	}
	
	@Test
	public void canHaveAsSquareTest_LegalCaseForWall(){
		Wall wall = new Wall(square1, square2, directionOfBorder, isSlipperyWall);
		assertTrue(wall.canHaveAsSquare(square4));
	}
	
//////////////////////////////////////////////////////////////////////////////////////////////////////
	
	@Test
	public void isValidDirectionTest_LegalCaseForDoor(){
		Door door = new Door(square1, square2, directionOfBorder, isClosedDoor);
		assertTrue(door.isValidDirection(directionOfBorder));
	}
	
	@Test
	public void isValidDirectionTest_LegalCaseForWall(){
		Wall wall = new Wall(square1, square2, directionOfBorder, isSlipperyWall);
		assertTrue(wall.isValidDirection(directionOfBorder));
		
	}
	
///////////////////////////////////////////////////////////////////////////////////////////////////////////
	
	@Test
	public void hasProperSquaresTest_LegalCaseForDoor(){
		Door door = new Door(square1, square2, directionOfBorder, isClosedDoor);
		assertTrue(door.hasProperSquares());
	}
	
	@Test
	public void hasProperSquaresTest_LegalCaseForWall(){
		Wall wall = new Wall(square1, square2, directionOfBorder, isSlipperyWall);
		assertTrue(wall.hasProperSquares());
	}
	
///////////////////////////////////////////////////////////////////////////////////////////////////////////
	
	@Test (expected = IllegalStateException.class)
	public void constructBorderTest_TerminatedDoorCase(){
		Door door = new Door(square1, directionOfBorder, isClosedDoor);
		door.terminate();
		door.constructBorder(square2, directionOfBorder);
	}	
	
	@Test (expected = IllegalArgumentException.class)
	public void constructBorderTest_InvalidDirectionForDoorCase(){
		Door door = new Door(square1, directionOfBorder, isClosedDoor);
		door.constructBorder(square2, null);
	}
	
	@Test (expected = IllegalArgumentException.class)
	public void constructBorderTest_NotCanHaveAsSquareForDoorCase(){
		Door door = new Door(square1, directionOfBorder, isClosedDoor);
		square2.terminate();
		door.constructBorder(square2, directionOfBorder);
	}
	
	@Test (expected = IllegalArgumentException.class)
	public void constructBorderTest_AlreadyHasAsSquareForDoorCase(){
		Door door = new Door(square1, directionOfBorder, isClosedDoor);
		door.constructBorder(square1, directionOfBorder);
	}
	
	@Test (expected = IllegalArgumentException.class)
	public void constructBorderTest_SquareToAttachToDoorAlreadyHasBorderCase(){
		Door door1 = new Door(square1, directionOfBorder, isClosedDoor);
		Door door2 = new Door(square2, directionOfBorder, isClosedDoor);
		door1.constructBorder(square2, directionOfBorder);
	}
	
	@Test (expected = IllegalArgumentException.class)
	public void constructBorderTest_NonEffectiveFirstSquareEffectiveSecondSquareIsNeighbourCase(){
		Door door1 = new Door(square1, square2, directionOfBorder, isClosedDoor);
		door1.getSquare1().terminate();
		Door door2 = new Door(square2, square3, directionOfBorder, isClosedDoor);
		assertTrue(square3.hasAsNeighbor(square2));
		door1.constructBorder(square3, directionOfBorder);
	}
	
	/**
	 * Case cannot be tested, method only occurs in constructor.
	 * This is already tested.
	 */
	@Test 
	public void constructBorderTest_NoneffectiveFirstSquareNonEffectiveSecondSquareCase(){
		
	}


	@Test
	public void constructBorderTest_NoneffectiveFirstSquareSecondSquareAttachedToThisDoorCase(){
		Door door = new Door(square1, square2, directionOfBorder, isClosedDoor);
		door.getSquare1().terminate();
		door.constructBorder(square3, directionOfBorder);
		assertEquals(square3, door.getSquare1());
	}
	
	@Test (expected = IllegalArgumentException.class)
	public void constructBorderTest_EffectiveFirstSquareNoneffectiveSecondSquareAlreadyNeighboursCase(){
		Door door1 = new Door(square1, directionOfBorder, isClosedDoor);
		Door door2 = new Door(square1, square3, directionOfBorder.getOpposite(), isClosedDoor);
		assertTrue(square3.hasAsNeighbor(door2.getSquare1()));
		door1.constructBorder(square3, directionOfBorder);
	}
	
	@Test
	public void constructBorderTest_EffectiveFirstSquareNonEffectiveSecondsquareMatchingBordersCase(){
		Door door = new Door (square1, directionOfBorder, isClosedDoor);
		door.constructBorder(square2, directionOfBorder.getOpposite());
		assertEquals(door.getSquare2(), square2);
	}
	
	@Test (expected = IllegalStateException.class)
	public void constructBorderTest_EffectiveFirstSquareEffectiveSecondSquareCase(){
		Door door = new Door(square1, square2, directionOfBorder, isClosedDoor);
		door.constructBorder(square3, directionOfBorder);
	}
	
/////////////////////////////////////////////////////////////////////////////////////////////////////	
//	@Test
//	public void setSquare1Test_CaseForDoorNoneffectiveSquareAndTerminatedDoor(){
//		Door door = new Door(square1, directionOfBorder, isClosedDoor);
//		Square FirstSquare = door.getSquare1();
//		door.setSquare1(null);
//		door.terminate();
//		assertEquals(null, FirstSquare);
//	}
//	
//	@Test
//	public void setSquare1Test_CaseForDoorNoneffectiveSquareAndTerminatedFirstSquare(){
//		Door door = new Door(square1, directionOfBorder, isClosedDoor);
//		Square FirstSquare = door.getSquare1();
//		door.setSquare1(null);
//		door.getSquare1().terminate();
//		assertEquals(null, FirstSquare);
//	}
//	
//	@Test
//	public void setSquare1Test_CaseForDoorPossibleSquareAndNoneffectiveFirstSquare(){
//		
//	}
////////////////////////////////////////////////////////////////////////////////////////////////////
//	@Test
//	public void setSquare1Test_CaseForWallNoneffectiveSquareAndTerminatedWall(){
//		Wall wall = new Wall(square1, directionOfBorder, isSlipperyWall);
//		Square FirstSquare = wall.getSquare1();
//		wall.setSquare1(null);
//		wall.terminate();
//		assertEquals(null, FirstSquare);		
//	}
//	
//	@Test
//	public void setSquare1Test_CaseForWallNoneffectiveSquareAndTerminatedFirstSquare(){
//		Wall wall = new Wall(square1, directionOfBorder, isSlipperyWall);
//		Square FirstSquare = wall.getSquare1();
//		wall.setSquare1(null);
//		walll.getSquare1().terminate();
//		assertEquals(null, FirstSquare);
//	}
//	
//	@Test
//	public void setSquare1Test_CaseForWallPossibleSquareAndNoneffectiveFirstSquare(){
//		
//	}
///////////////////////////////////////////////////////////////////////////////////////////////////	
//	@Test
//	public void setSquare2Test_CaseForDoorNoneffectiveSquareAndTerminatedDoor(){
//		
//	}
//	
//	@Test
//	public void setSquare2Test_CaseForDoorNoneffectiveSquareAndTerminatedSecondSquare(){
//		
//	}
//	
//	@Test
//	public void setSquare2Test_CaseForDoorPossibleSquareAndNoneffectiveSecondSquare(){
//		
//	}
////////////////////////////////////////////////////////////////////////////////////////////////////
//	@Test
//	public void setSquare2Test_CaseForWallNoneffectiveSquareAndTerminatedWall(){
//		
//	}
//	
//	@Test
//	public void setSquare2Test_CaseForWallNoneffectiveSquareAndTerminatedSecondSquare(){
//		
//	}
//	
//	@Test
//	public void setSquare2Test_CaseForWallPossibleSquareAndNoneffectiveSecondSquare(){
//		
//	}
/////////////////////////////////////////////////////////////////////////////////////////////////////
	@Test
	public void hasAsSquareTest_LegalCaseForDoor(){
		Door door = new Door(square1, square2, directionOfBorder, isClosedDoor);
		assertFalse(door.hasAsSquare(square3));
		assertFalse(door.hasAsSquare(square4));
		assertTrue(door.hasAsSquare(square1));
		assertTrue(door.hasAsSquare(square2));
	}
	
	@Test
	public void hasAsSquareTest_LegalCaseForWall(){
		Wall wall = new Wall(square1, square2, directionOfBorder, isSlipperyWall);
		assertFalse(wall.hasAsSquare(square3));
		assertFalse(wall.hasAsSquare(square4));
		assertTrue(wall.hasAsSquare(square1));
		assertTrue(wall.hasAsSquare(square2));
	}

///////////////////////////////////////////////////////////////////////////////////////////////////////
	
	@Test
	public void detachTest_LegalCaseForDoorFirstSquareEffectiveSecondSquare(){
		Door door = new Door(square1, square2, directionOfBorder, isClosedDoor);
		square1.terminate();
		assertEquals(door.getSquare1(), null);
	}
	
	@Test
	public void detachTest_LegalCaseForDoorFirstSquareNoneffectiveSecondSquare(){
		Door door = new Door(square1, directionOfBorder, isClosedDoor);
		square1.terminate();
		assertTrue(door.isTerminated());
	}
	
	@Test (expected = AssertionError.class)
	public void detachTest_IllegalCase(){
		square1.getBorder(Direction.FLOOR).terminate();
	}
	
	@Test
	public void detachTest_LegalCaseForDoorSecondSquareEffectiveFirstSquare(){
		Door door = new Door(square1, square2, directionOfBorder, isClosedDoor);
		square2.terminate();
		assertEquals(door.getSquare2(), null);
	}
	
	@Test
	public void detachTest_LegalCaseForDoorSecondSquareNoneffectiveFirstSquare(){
		Door door = new Door(square1, square2, directionOfBorder, isClosedDoor);
		square1.terminate();
		square2.terminate();
		assertTrue(door.isTerminated());
		
	}
	
	@Test
	public void detachTest_LegalCaseForWallFirstSquareEffectiveSecondSquare(){
		Wall wall = new Wall(square1, square2, directionOfBorder, isSlipperyWall);
		square1.terminate();
		assertEquals(wall.getSquare1(), null);
	}
	
	@Test
	public void detachTest_LegalCaseForWallFirstSquareNoneffectiveSecondSquare(){
		Wall wall = new Wall(square1, directionOfBorder, isSlipperyWall);
		square1.terminate();
		assertTrue(wall.isTerminated());
	}
	
	@Test
	public void detachTest_LegalCaseForWallSecondSquareEffectiveFirstSquare(){
		Wall wall = new Wall(square1, square2, directionOfBorder, isSlipperyWall);
		square2.terminate();
		assertEquals(wall.getSquare2(), null);
	}
	
	@Test
	public void detachTest_LegalCaseForWallSecondSquareNoneffectiveFirstSquare(){
		Wall wall = new Wall(square1, square2, directionOfBorder, isSlipperyWall);
		square1.terminate();
		square2.terminate();
		assertTrue(wall.isTerminated());
	}
	
/////////////////////////////////////////////////////////////////////////////////////////////
	
	private NormalSquare square1;
	private NormalSquare square2;
	private NormalSquare square3;
	private NormalSquare square4;
	private Direction directionOfBorder;
	private boolean isClosedDoor;
	private boolean isSlipperyWall;
	
	
	
}
